package org.nf.web.servlet.adapter;

import cn.hutool.core.util.ReflectUtil;
import org.nf.web.servlet.*;
import org.nf.web.servlet.param.MethodArgumentResolverComposite;
import org.nf.web.servlet.view.DefaultView;

import java.lang.reflect.Parameter;
import java.util.ServiceLoader;

/**
 * @author wangliang
 * @date 2023/4/19
 */
public class RequestMappingHandlerAdapter implements HandlerAdapter {

    /**
     * 参数解析器组合
     */
    private final MethodArgumentResolverComposite argumentResolvers = new MethodArgumentResolverComposite();

    /**
     * 初始化参数解析器
     */
    public RequestMappingHandlerAdapter() {
        //加载用户自定义的参数解析器
        FrameworkContext.getInstance().getClasses().stream()
                .filter(MethodArgumentResolver.class::isAssignableFrom)
                .forEach(resolverClass -> argumentResolvers.addResolver((MethodArgumentResolver) ReflectUtil.newInstance(resolverClass)));
        //加载在框架的参数解析器
        ServiceLoader.load(MethodArgumentResolver.class).forEach(argumentResolvers::addResolver);
    }

    @Override
    public boolean supports(Object handler) {
        return handler instanceof HandlerMethod;
    }

    @Override
    public BaseView handle(Object handler, ServletApi servletApi) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        //请求处理方法参数解析,返回一个转解析好的arguments数组
        Object[] arguments = resolveMethodArguments(handlerMethod.parameters(), servletApi);
        //调用controller方法
        return invokeHandlerMethod(handlerMethod, arguments);
    }

    /**
     * 解析方法参数
     */
    private Object[] resolveMethodArguments(Parameter[] parameters, ServletApi servletApi) throws Exception {
        //定义一个Object数组，用于存解析换后的值
        Object[] values = new Object[parameters.length];
        //循环参数信息
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            //解析参数
            if(argumentResolvers.supports(parameter)) {
                values[i] = argumentResolvers.resolve(parameter, servletApi);
                //如果参数的值为空并且参数的类型是基本数据类型，则不能直接赋值，必须抛出异常
                if (values[i] == null && parameter.getType().isPrimitive()) {
                    throw new IllegalArgumentException("Can not set " + parameter.getType().getName() + " type argument to null value.");
                }
            }
        }
        return values;
    }

    /**
     * 调用Controller中的请求处理方法
     */
    private BaseView invokeHandlerMethod(HandlerMethod handlerMethod, Object[] arguments) {
        //获取声明请求处理方法的类型（也就是Controller类），并创建实例
        Object instance = ReflectUtil.newInstance(handlerMethod.handlerClass());
        //执行方法回调并返回视图结果
        Object result = ReflectUtil.invoke(instance, handlerMethod.method(), arguments);
        BaseView view = null;
        if (result != null) {
            //如果返回的result是View的实例则强转返回，否则将result包装为HTML视图处理
            view = (result instanceof BaseView) ? (BaseView) result : new DefaultView(result);
        }
        return view;
    }
}
